package co.edu.poli.ficb.agl.automatable.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.TitledBorder;

import co.edu.poli.ficb.agl.automatable.modelo.SimboloImpl;
import co.edu.poli.ficb.agl.automatable.modelo.automatas.Automata;
import co.edu.poli.ficb.agl.automatable.modelo.automatas.AutomataFinitoImpl;
import co.edu.poli.ficb.agl.automatable.modelo.automatas.Estado;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
import edu.uci.ics.jung.algorithms.util.IterativeContext;
import edu.uci.ics.jung.visualization.layout.LayoutTransition;
import edu.uci.ics.jung.visualization.util.Animator;

/**
 * 
 * @author Diego David Satoba Castro
 * @version 0.1 
 *
 */
@SuppressWarnings("serial")
public class PanelEjecucionAutomata extends JPanel implements ActionListener, KeyListener {
	
	private PanelAutomata2 panelAutomata;
	
	private int index = -1;
	
	private String cadena;
	
	private JPanel pCadena;
	
	private JTextField[] tfields;
	
	private JButton bPrev;
	
	private JButton bNext;
	
	private JButton bStop;
	
	private JButton bPlay;
	
	private JButton bRun;
	
	private JButton bPause;
	
	private JButton bEntrar;
	
	private JTextField tfCadena;
	
	private JScrollPane jsp;

	private Timer timer;

	private boolean hecho;
	
	private JLabel labelResultado;

	public PanelEjecucionAutomata(PanelAutomata2 panelAutomata) {
		super();
		this.cadena = "";
		this.panelAutomata = panelAutomata;
		init();
	}

	private void init() {
		pCadena = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 20));
		
		Font font = new Font("monospaced", Font.PLAIN, 12);
		
		labelResultado = new JLabel();
		
		JPanel pControl = new JPanel(new FlowLayout());
		bPlay = new JButton(">");
		bPlay.setFont(font);
		bPlay.setActionCommand("play");
		bPlay.addActionListener(this);
		
		bRun = new JButton(">>");
		bRun.setFont(font);
		bRun.setActionCommand("run");
		bRun.addActionListener(this);
		
		bPause = new JButton("||");
		bPause.setFont(font);
		bPause.setActionCommand("pause");
		bPause.addActionListener(this);
		bPause.setEnabled(false);
		
		bStop = new JButton("[]");
		bStop.setFont(font);
		bStop.addActionListener(this);
		bStop.setActionCommand("stop");
		bStop.setEnabled(false);
		
		bNext = new JButton("->");
		bNext.setFont(font);
		bNext.setActionCommand("next");
		bNext.addActionListener(this);
		bNext.setEnabled(false);
		
		
		bPrev = new JButton("<-");
		bPrev.setFont(font);
		bPrev.setActionCommand("prev");
		bPrev.addActionListener(this);
		bPrev.setEnabled(false);
		
		pControl.add(bPlay);
		pControl.add(bPause);
		pControl.add(bRun);
		pControl.add(bStop);
		pControl.add(bPrev);
		pControl.add(bNext);
		
		JPanel pEntrada = new JPanel(new FlowLayout());
		
		bEntrar = new JButton(">");
		bEntrar.setActionCommand("entrar");
		bEntrar.addActionListener(this);
		
		tfCadena = new JTextField();
		tfCadena.setFont(new Font("monospaced", Font.PLAIN, 12));
		tfCadena.setColumns(32);
		tfCadena.setActionCommand("cadena");
		tfCadena.addKeyListener(this);
		
		pEntrada.add(tfCadena);
		pEntrada.add(bEntrar);
		pEntrada.add(labelResultado);
		
		jsp = new JScrollPane();
		
		setLayout(new BorderLayout());
		add(pEntrada, BorderLayout.NORTH);
		add(jsp, BorderLayout.CENTER);
		add(pControl, BorderLayout.SOUTH);
		setPreferredSize(new Dimension(512,180));
		setBorder(new TitledBorder("Ejecutar"));
	}
	
	private void iniciarCadena() {
		cadena = SimboloImpl.LAMBDA+tfCadena.getText();
		pCadena.removeAll();
		tfields = new JTextField[cadena.length()];
		Font font = new Font("monospaced", Font.PLAIN, 18);
		for (int i=0; i<cadena.length(); i++) {
			char c = cadena.charAt(i);
			JTextField tf = new JTextField();
			//tf.setColumns(1);
			tf.setDisabledTextColor(Color.BLUE);
			tf.setEnabled(false);
			tf.setFont(font);
			tf.setText(String.valueOf(c));
			tf.setPreferredSize(new Dimension(30, 30));
			tf.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
			//tf.//setVerticalAlignment(javax.swing.SwingConstants.CENTER);
			tfields[i] = tf;
			pCadena.add(tf);
		}
		tfields[0].setBorder(BorderFactory.createEmptyBorder());
		pCadena.validate();
		remove(jsp);
		jsp = new JScrollPane(pCadena);
		jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
		add(jsp, BorderLayout.CENTER);
		labelResultado.setText("");
		validate();
	}
	
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.getContentPane().add(new PanelEjecucionAutomata(new PanelAutomata2(new AutomataFinitoImpl())));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		frame.pack();
	}
	
	private int longitudCadena() {
		return cadena.length();
	}
	
	public void play() {
		if (index == -1) { // inicia:
			index = 0;
		}
		tfields[index].setBackground(Color.YELLOW);
		
		bPlay.setEnabled(false);
		
		bPrev.setEnabled(true);
		bNext.setEnabled(true);
		bPause.setEnabled(true);
		bStop.setEnabled(true);
		
		panelAutomata.iniciarSimulacion();
	}
	
	private void next() {
		tfields[index].setBackground(Color.WHITE);
		tfields[++index].setBackground(Color.YELLOW);
		tfields[index].requestFocusInWindow();
		if (index == longitudCadena()-1) {
			bNext.setEnabled(false);
			bPause.setEnabled(false);
		} else if (index > 0) {
			bPrev.setEnabled(true);
		}
		panelAutomata.ejecutarPaso(cadena.charAt(index));
		//ubicarScrollPane();
	}
	
	private void ubicarScrollPane() {
		//getLayout().
	}

	private void prev() {
		if (index > 0) {
			tfields[index].setBackground(Color.WHITE);
			tfields[--index].setBackground(Color.YELLOW);
		}
		if (index == 0) {
			bPrev.setEnabled(false);
		} else if (index < longitudCadena()-1) {
			bNext.setEnabled(true);
		}
	}
	
	public void stop() {
		if (index != -1) {
			tfields[index].setBackground(Color.white);
			index = -1;
		}
		bPlay.setEnabled(true);
		bStop.setEnabled(false);
		bNext.setEnabled(false);
		bPrev.setEnabled(false);
		bPause.setEnabled(false);
		
		panelAutomata.detenerSimulacion();
	}
	
	private void pause() {
		bPlay.setEnabled(true);
		bPause.setEnabled(false);
		bPrev.setEnabled(false);
		bNext.setEnabled(false);
	}
	
	private void playAuto() {
		if (index == -1) { // inicia:
			index = 0;
		}
		tfields[index].setBackground(Color.YELLOW);
		
		bPlay.setEnabled(false);
		bPause.setEnabled(false);
		bStop.setEnabled(true);
		bNext.setEnabled(false);
		bPrev.setEnabled(false);
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		String action = e.getActionCommand();
		if ("next".equals(action)) {
			next();
		} else if ("play".equals(action)) {
			play();
		} else if ("prev".equals(action)) {
			prev();
		} else if ("stop".equals(action)) {
			stop();
		} else if ("pause".equals(action)) {
			pause();
		} else if ("entrar".equals(action)) {
			stop();
			iniciarCadena();
		} else if ("run".equals(action)) {
			iniciarSimulacionAutomatica();
		}
	}

	private void run() {
		//jsp.getViewport().setViewPosition(new Point(50, 50));
	}

	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			stop();
			iniciarCadena();
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) {}

	@Override
	public void keyTyped(KeyEvent arg0) {}
	
	public void iniciarSimulacionAutomatica() {
		hecho = false;
		timer = new Timer();
		timer.schedule(new RemindTask(), 1000, 1000);
		stop();
		playAuto();
		panelAutomata.iniciarSimulacion();
	}
	
	private void procesar() {
		if (index < cadena.length()-1) {
            next();
		} else {
			hecho = true;
			mostrarResultado();
			stop();
		}
	}
	
	private void mostrarResultado() {
		boolean es = false;
		Automata automata = panelAutomata.getAutomata();
		if (0 <= index && index <= cadena.length()) {
			for (Estado estado : panelAutomata.getControlador().estadosEnPaso(index)) {
				if (automata.getEstadosAceptacion().contains(estado)) {
					es = true;
					break;
				}
			}
		}
		labelResultado.setText("esta cadena "+(es?"":"no")+" pertence a L(M).");
	}
	
	class RemindTask extends TimerTask {
        @Override
        public void run() {
            procesar();
            if (hecho) 
            	cancel();
        }
    }
}
